;;; Code:
;; Buffer-related defuns
(require 's)

;;;###autoload
(defun distopico:enable--recreate-scratch-buffer ()
  "Make sure scratch has the correct `initial-major-mode' and custom actions."
  (with-current-buffer "*scratch*"
    (funcall initial-major-mode)
    (add-hook 'kill-buffer-query-functions 'distopico:recreate--scratch-buffer nil t)))

;;;###autoload
(defun distopico:recreate--scratch-buffer ()
  "If the *scratch* buffer is killed, recreate it automatically.
FROM: Morten Welind: http://www.geocrawler.com/archives/3/338/1994/6/0/1877802/"
  ;; The next line is just in case someone calls this manually
  (set-buffer (get-buffer-create "*scratch*"))
  ;; Kill the current (*scratch*) buffer
  (remove-hook 'kill-buffer-query-functions 'distopico:recreate--scratch-buffer t)
  (kill-buffer (current-buffer))
  ;; Make a brand new *scratch* buffer
  (distopico:create-scratch-buffer)
  ;; Should return nil to avoid loop
  nil)

;;;###autoload
(defun distopico:create-scratch-buffer nil
  "Create a new scratch buffer to work in.
Could be *scratch* - *scratchX*."
  (interactive)
  (let ((n 0)
        bufname)
    (while (progn
             (setq bufname (concat "*scratch"
                                   (if (= n 0) "" (int-to-string n))
                                   "*"))
             (setq n (1+ n))
             (get-buffer bufname)))
    (switch-to-buffer (get-buffer-create bufname))
    (message (format "Created %s" bufname))
    (distopico:enable--recreate-scratch-buffer)
    (insert initial-scratch-message)))

(defun split-window-right-and-move-there-dammit ()
  (interactive)
  (split-window-right)
  (windmove-right))

(defun kill-this-buffer-and-pane ()
  "If there are multiple windows, then close this pane and kill the buffer in it also.
   from: http://www.emacswiki.org/emacs/KillingBuffers"
  (interactive)
  (kill-this-buffer)
  (if (not (one-window-p))
      (delete-window)))

(defun kill-next-buffer-and-pane ()
  "If there are multiple windows, then close the other pane and kill the buffer in it also.
  from: http://www.emacswiki.org/emacs/KillingBuffers"
  (interactive)
  (other-window 1)
  (kill-this-buffer)
  (if (not (one-window-p))
      (delete-window)))

(defun toggle-window-split ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
             (next-win-buffer (window-buffer (next-window)))
             (this-win-edges (window-edges (selected-window)))
             (next-win-edges (window-edges (next-window)))
             (this-win-2nd (not (and (<= (car this-win-edges)
                                         (car next-win-edges))
                                     (<= (cadr this-win-edges)
                                         (cadr next-win-edges)))))
             (splitter
              (if (= (car this-win-edges)
                     (car (window-edges (next-window))))
                  'split-window-horizontally
                'split-window-vertically)))
        (delete-other-windows)
        (let ((first-win (selected-window)))
          (funcall splitter)
          (if this-win-2nd (other-window 1))
          (set-window-buffer (selected-window) this-win-buffer)
          (set-window-buffer (next-window) next-win-buffer)
          (select-window first-win)
          (if this-win-2nd (other-window 1))))))

(defun rotate-windows ()
  "Rotate your windows"
  (interactive)
  (cond ((not (> (count-windows)1))
         (message "You can't rotate a single window!"))
        (t
         (setq i 1)
         (setq numWindows (count-windows))
         (while  (< i numWindows)
           (let* (
                  (w1 (elt (window-list) i))
                  (w2 (elt (window-list) (+ (% i numWindows) 1)))

                  (b1 (window-buffer w1))
                  (b2 (window-buffer w2))

                  (s1 (window-start w1))
                  (s2 (window-start w2))
                  )
             (set-window-buffer w1  b2)
             (set-window-buffer w2 b1)
             (set-window-start w1 s2)
             (set-window-start w2 s1)
             (setq i (1+ i)))))))

(defun get-buffers-with-major-mode (mode)
  "Returns list of buffers with major-mode MODE or derived from MODE."
  (cl-loop
   for buf in (buffer-list)
   if (and (buffer-live-p buf)
           (with-current-buffer buf
             (derived-mode-p mode)))
   collect buf))

(defun transpose-windows (arg)
  "Transpose the buffers shown in two windows."
  (interactive "p")
  (let ((selector (if (>= arg 0)
                      'next-window
                    'previous-window)))
    (while (/= arg 0)
      (let ((this-win (window-buffer))
            (next-win (window-buffer (funcall selector))))
        (set-window-buffer (selected-window) next-win)
        (set-window-buffer (funcall selector) this-win)
        (select-window (funcall selector)))
      (setq arg (if (plusp arg)
                    (1- arg)
                  (1+ arg))))))

(defun untabify-buffer ()
  (interactive)
  (untabify (point-min) (point-max)))

(defun indent-buffer ()
  (interactive)
  (indent-region (point-min) (point-max)))

(defun cleanup-buffer ()
  "Perform a bunch of operations on the whitespace content of a buffer.
Including indent-buffer, which should not be called automatically on save."
  (interactive)
  (untabify-buffer)
  (indent-buffer))

(defun file-name-with-one-directory (file-name)
  (concat (cadr (reverse (split-string file-name "/"))) "/"
          (file-name-nondirectory file-name)))


(defvar user-home-directory (concat (expand-file-name "~") "/"))
;;Recent open
(defun recentf--file-no-prefix (file-name)
  (cons (s-chop-prefix user-home-directory file-name) file-name))

(defun recentf-find-file ()
  "Find a recent file using ido."
  (interactive)
  (let* ((recent-files (mapcar 'recentf--file-no-prefix recentf-list))
         (files (mapcar 'car recent-files))
         (file (completing-read "Choose recent file: " files)))
    (find-file (cdr (assoc file recent-files)))))

(defun ido-recentf-open ()
  "Use `ido-completing-read' to \\[find-file] a recent file."
  (interactive)
  (let* ((recent-files (mapcar 'recentf--file-no-prefix recentf-list))
         (files (mapcar 'car recent-files))
         (file (ido-completing-read "Find recent file:: " files)))
    (find-file (cdr (assoc file recent-files)))))

(defun switch-to-minibuffer ()
  "Make the active minibuffer the selected window."
  (interactive)
  (when (active-minibuffer-window)
    (select-window (active-minibuffer-window))))

(defun switch-to-previous-buffer ()
  "Switch to previously open buffer.
Repeated invocations toggle between the two most recently open buffers
from: http://emacsredux.com/blog/2013/04/28/switch-to-previous-buffer/"
  (interactive)
  (switch-to-buffer (other-buffer (current-buffer) 1)))

(defun open-buffer-delete-others(buffer-name register-name action &optional open-same-window)
  "Open `BUFFER-NAME' in fullscreen and delete other windows.
`BUFFER-NAME': NAME of buffer, `NAME-REGISTER': name to register current window
action: the action execute, optional, open-same-window"
  (if (not (equal (buffer-name) buffer-name))
      (progn
        (window-configuration-to-register register-name)
        (let ((name-buffer (get-buffer buffer-name)))
          (if name-buffer
              (if open-same-window
                  (switch-to-buffer name-buffer)
                (switch-to-buffer-other-window name-buffer))
            (funcall action)))
        (delete-other-windows))))

(defun bury-buffer-restore-prev (register-name)
  "Restore the previous window configuration by `REGISTER-NAME' and bury buffer."
  (interactive)
  (bury-buffer)
  (jump-to-register-and-remove register-name))

(defun jump-to-register-and-remove (register-name)
  "Jump to `REGISTER-NAME' if exists and remove register."
  (let ((register (get-register register-name)))
    (when register
      (jump-to-register register-name)
      (delete-register register-name))))

(defun delete-register (register-name)
  "Delete `REGISTER-NAME' if exists."
  (let ((register (get-register register-name)))
    (when register
      (setq register-alist (delete (cons register-name register) register-alist)))))

;; code from https://gist.github.com/anonymous/1061884
(defun auto-byte-recompile ()
  "Recompile if the current buffer is `emacs-lisp-mode'.
If exists an `.elc' file corresponding to the current buffer file,
then recompile the file."
  (interactive)
  (when (and (eq major-mode 'emacs-lisp-mode)
             (file-exists-p (byte-compile-dest-file buffer-file-name)))
    (byte-compile-file buffer-file-name)))

;; Compiled  lips files
(defun byte-compile-init-dir ()
  "Byte-compile all your dotfiles."
  (interactive)
  (byte-recompile-directory user-emacs-directory 0))

(defun byte-compile-when-save()
  "When save, recompile it if already have compile file"
  (make-local-variable 'after-save-hook)
  (add-hook 'after-save-hook
            (lambda ()
              (if (file-exists-p (concat buffer-file-name "c"))
                  (byte-compile-file buffer-file-name)))))

(provide 'buffer-defuns)
